<?php
/**********************************************************************************
WIKINDX: Bibliographic Management system.
Copyright (C)

This program is free software; you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program;
if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

The WIKINDX Team 2006
sirfragalot@users.sourceforge.net
**********************************************************************************/
/*****
*	ENDNOTE (XML >= Endnote v8) export class
*
*	$Header: /cvsroot/wikindx/wikindx3/core/file/export/ENDNOTEXML.php,v 1.2 2006/04/23 02:34:24 sirfragalot Exp $
*****/
class ENDNOTEXML
{
/*
* Constructor
*
* @author Mark Grimshaw
* @version 2
*/
// Constructor
	function ENDNOTEXML($db, $vars)
	{
		$this->db = $db;
		$this->vars = $vars;
		include_once("core/file/FILE.php");
		$this->file = new FILE($this->db);
		include_once("core/template/TEMPLATE.php");
		$this->template = new TEMPLATE('content');
		include_once("core/messages/ERRORS.php");
		$this->errors = new ERRORS();
		include_once("core/messages/MESSAGES.php");
		$this->messages = new MESSAGES();
		include_once("core/session/SESSION.php");
		$this->session = new SESSION();
		include_once("core/file/ENDNOTEMAP.php");
		$this->map = new ENDNOTEMAP();
		include_once("core/file/export/EXPORTCOMMON.php");
		$this->common = new EXPORTCOMMON($this->db);
//		include_once("core/messages/UTF8.php");
//		$this->utf8 = new UTF8();
// Perform some system admin
		$this->file->tidyFiles();
	}
// Stage 1 - present export options
	function stage1()
	{
		$this->template->setVar('heading', $this->messages->text("heading", "exportEndnoteXml"));
		if(!$sql = $this->session->getVar('sql_stmt'))
			$this->failure($this->errors->text("file", "noSql"));
		$pString = FORM::formHeader("exportEndnoteXml");
		$checked = $this->session->getVar("export_mergeStored") ? TRUE : FALSE;
		$pString .= MISC::p($this->messages->text("misc", "mergeStored") . "&nbsp;&nbsp;" . 
			FORM::checkbox(FALSE, "mergeStored", $checked));
		$pString .= $this->common->getCustomFields($sql);
		$pString .= MISC::br() . FORM::formSubmit('Submit');
		$pString .= FORM::formEnd();
		$this->template->setVar('body', $pString);
		return $this->template->process();
	}
// write $this->pString to file.  If file exists, it is written over.
	function process()
	{
		if(isset($this->vars['mergeStored']))
			$this->session->setVar('export_mergeStored', $this->vars['mergeStored']);
		else
			$this->session->delVar('export_mergeStored');
		$this->customIds = $checkDuplicates = array();
		$duplicateMapping = FALSE;
		foreach($this->vars as $key => $value)
		{
			$split = explode("map_", $key);
			if(sizeof($split) == 2)
			{
				$value = trim($value);
				if($value)
				{
					$this->session->setVar("export_$key", $value);
					if(!$duplicateMapping && (array_search(strtolower($value), $checkDuplicates) !== FALSE))
						$duplicateMapping = TRUE;
					$this->customIds[$split[1]] = $value;
					$checkDuplicates[] = strtolower($value);
				}
				else
					$this->session->delVar("export_$key");
			}
		}
		unset($checkDuplicates);
		$this->template->setVar('heading', $this->messages->text("heading", "exportEndnoteXml"));
// if duplicate custom mapping found, fail
		if($duplicateMapping)
			$this->failure($this->errors->text("inputError", "duplicateCustomMap"));
		$this->xmlHeader();
		$this->getData();
		$this->xmlFooter();
		list($fileName, $fullFileName) = $this->file->createFileName($this->pString, '.xml');
		if(!$fullFileName)
			$this->failure($this->errors->text("file", "write", ": $fileName"));
		if(!$fp = fopen("$fullFileName", "w"))
			$this->failure($this->errors->text("file", "write", ": $fileName"));
		if(!fputs($fp, $this->pString))
			$this->failure($this->errors->text("file", "write", ": $fileName"));
		fclose($fp);
		$this->common->writeFilenameToSession($fileName);
		$pString = $this->common->listFiles();
		$this->template->setVar('body', $pString);
		return $this->template->process();
	}
// XML headers strings
	function xmlHeader()
	{
		$this->pString = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?><xml><records>"; 
	}
// XML footer strings
	function xmlFooter()
	{
		$this->pString .= "</records></xml>";
	}
// get data from database
	function getData()
	{
// load default arrays (English constants, day and month conversions etc.
		$this->loadArrays();
// Get all possible field names from $this->map
		$fieldNameArray = array_keys($this->map->endnoteXmlFields8);
		$exportRawFields = $this->map->exportRawFieldsXml;
// Get last SQL statement from session.
		if(!$sql = $this->session->getVar('sql_stmt'))
			$this->failure($this->errors->text("file", "noSql"));
		$customSelect = FALSE;
		if(!empty($this->customIds))
		{
			$condition = "WHERE (" . $this->db->formatfield('customId') . "=" . 
				join(" OR " . $this->db->formatfield('customId') . "=", array_keys($this->customIds)) . ")";
			$customSelect = $this->db->selectNoExecute(array('WKX_resource_custom'), 
				array('customId', 'resourceId', 'custom_long', 'custom_short'), $condition);
		}
		$recordset = $this->db->query(stripslashes($sql));
/**
* Need to get raw data first and add its keys to $fieldNameArray
**/
		if($this->session->getVar("export_mergeStored"))
		{
			while($row = $this->db->loopRecordSet($recordset))
			{
				if($raw = $this->raw($row))
				{
					foreach($raw as $key => $value)
					{
						if(!array_key_exists($key, $exportRawFields))
							continue;
						$key = $exportRawFields[$key];
						if(array_search($key, $fieldNameArray) === FALSE)
							$fieldNameArray[] = $key;
					}
					$rawEntries[$row['resourceId']] = $raw;
				}
			}
		}
		$recordset = $this->db->query(stripslashes($sql));
		while($row = $this->db->loopRecordSet($recordset))
		{
			$this->authorFound = FALSE;
			$lineArray = $this->rawEntries = $contributors = $titles = array();
			$this->pString .= "<record>";
// Do we need to switch `year1` (publicationYear) and `year2` (reprintYear)
			if((($row['type'] == 'book') || ($row['type'] == 'book_article'))
				&& $row['year1'] && $row['year2'])
			{
				$tempYear2 = $row['year2'];
				$row['year2'] = $row['year1'];
				$row['year1'] = $tempYear2;
			}
// else, always use `year2` (conference year etc.) in preference to `year1` except for web_article
			else if($row['year2'] && ($row['type'] != 'web_article'))
			{
				$row['year1'] = $row['year2'];
				unset($row['year2']);
			}
// Handle dates
			if($dates = $this->dateFormat($row))
				$this->pString .= $dates;
			foreach($this->map->{$row['type']} as $table => $tableArray)
			{
				if($table == 'resource_creator') // this is done later
					continue;
				foreach($tableArray as $wkField => $enField)
				{
					$field = array_search($enField, $this->map->endnoteXmlFields8);
					if(($field !== FALSE) && isset($row[$wkField]) && $row[$wkField])
					{
						if(($field == 'secondary-title') || ($field == 'tertiary-title') || 
							($field == 'alt-title') || ($field == 'short-title'))
							$titles[] = "<$field><style>" . $this->spCharFormat(stripSlashes($row[$wkField])) . 
							"</style></$field>";
						else if($field == 'url')
							$this->pString .= "<urls><related-urls><$field><style>" . 
							$this->spCharFormat(stripSlashes($row[$wkField])) . 
							"</style></$field></related-urls></urls>";
						else
							$this->pString .= "<$field><style>" . 
							$this->spCharFormat(stripSlashes($row[$wkField])) . "</style></$field>";
					}
				}
			}
// The title
			$titles[] = "<title><style>" . $this->spCharFormat($this->common->titleFormat($row)) . 
				"</style></title>";
			$this->pString .= "<titles>" . join('', $titles) . "</titles>";
// Authors
			foreach($this->map->{$row['type']}['resource_creator'] as $wkCreator => $enCreator)
			{
				if(!$creators = $this->nameFormat($row, $wkCreator))
					continue;
				$contributors[] = $creators;
			}
			if(!empty($contributors))
				$this->pString .= "<contributors>" . join("", $contributors) . "</contributors>";
// Reference Type.  If !$this->authorFound and $row['type'] == 'book', this is actually 
// Endnote's 'Edited Book' type.
			if(!$this->authorFound and ($row['type'] == 'book'))
				$this->pString .= "<source-app name=\"EndNote\" version=\"8.0\">EndNote</source-app><ref-type name=\"Edited Book\">28</ref-type>";
			else
			{
				if(!array_key_exists($row['type'], $this->map->exportTypes8))
				{
					$refType = 'Generic';
					$refNum = 13;
				}
				else
				{
					$refType = $this->map->types[$row['type']];
					$refNum = $this->map->exportTypes8[$row['type']];
				}
				$this->pString .= "<source-app name=\"EndNote\" version=\"8.0\">EndNote</source-app><ref-type name=\"$refType\">$refNum</ref-type>";
			}
			if($output = $this->spCharFormat($this->common->pageFormat($row, 'endnote')))
				$this->pString .= "<pages><style>$output</style></pages>";
			if($output = $this->common->keywordFormat($row, 'endnoteXml'))
				$this->pString .= "<keywords>$output</keywords>";
			if($output = $this->spCharFormat($this->common->grabAbstract($row, 'endnote')))
				$this->pString .= "<abstract><style>$output</style></abstract>";
			if($output = $this->spCharFormat($this->common->grabNote($row, 'endnote')))
				$this->pString .= "<notes><style>$output</style></notes>";
// Do we want to export previously saved unused fields?
			if(!empty($rawEntries) && array_key_exists($row['resourceId'], $rawEntries))
			{
				foreach($rawEntries[$row['resourceId']] as $key => $value)
				{
					if(array_key_exists($key, $exportRawFields))
						$this->pString .= "<$key><style>" . $this->spCharFormat($value) . "</style></$key>";
				}
			}
// Deal with any custom field mappings
			if($customSelect)
			{
				$customset = $this->db->query($customSelect . " AND " . 
					$this->db->formatfield('resourceId') . '=' . $row['resourceId']);
				while($customRow = $this->db->loopRecordSet($customset))
				{
					$fieldName = str_replace(' ', '', $this->customIds[$customRow['customId']]);
					if($customRow['custom_short'])
						$this->pString .= "<$fieldName><style>" . 
						$this->spCharFormat($customRow['custom_short']) . "</style></$fieldName>";
					if($customRow['custom_long'])
						$this->pString .= "<$fieldName><style>" . 
						$this->spCharFormat($customRow['custom_long']) . "</style></$fieldName>";
				}
			}
			$this->pString .= "</record>";
		}
	}
// Format special characters for XML
	function spCharFormat($string)
	{
		$match = array("/&/", '/"/', "/'/", "/</", "/>/");
		$replace = array("&amp;", "&quot;", "&apos;", "&lt;", "&gt;");
		$string = preg_replace($match, $replace, $string);
		return preg_replace("/\[.*\]|\[\/.*\]/U", "", $string);
	}
// format names.
	function nameFormat($row, $type)
	{
		if(!isset($row[$type]) || !$row[$type])
			return '';
		$xmlAuthorType = array_search($this->map->{$row['type']}['resource_creator'][$type], 
			$this->map->endnoteXmlFields8);
		if($xmlAuthorType === FALSE)
			return '';
		if($type == 'creator1') // author
			$this->authorFound = TRUE;
		$creatorIds = explode(",", $row[$type]);
		foreach($creatorIds as $id)
			$condition[] = $this->db->formatField('id') . "=" . $this->db->tidyInput($id);
		$recordset = $this->db->select(array('WKX_creator'), 
			array('surname', 'firstname', 'initials', 'prefix', 'id'), 
			" WHERE " . implode(' OR ', $condition));
		if($this->db->numRows($recordset))
		{
			$nameArray = array();
			while($creatorRow = $this->db->loopRecordset($recordset))
			{
				$name = $this->common->formatName($creatorRow, 'endnote');
				if($name)
					$mapName[$creatorRow['id']] = $name;
			}
			foreach($creatorIds as $id)
				$nameArray[] = "<author><style>" . $mapName[$id] . "</style></author>";
			return "<$xmlAuthorType>" .  join("", $nameArray) . "</$xmlAuthorType>";
		}
		return ''; // just in case
	}
// format date for newspaper/magazine etc.
// web_article Access Year is stored in 'Volume' and Access Date in 'Number'.  Why?
	function dateFormat(&$row)
	{
		$day = $month = FALSE;
		$dates = array();
		if($row['type'] == 'web_article')
// Access Year -> 'Volume' and access date -> 'Number'
		{
			if($row['miscField3'])
			{
				$month = $this->monthArray[$row['miscField3']];
				unset($row['miscField3']);
			}
			if($row['miscField2'])
			{
				$day = $row['miscField2'] < 10 ? '0' . $row['miscField2'] : $row['miscField2'];
				unset($row['miscField2']);
			}
			if($month)
				$this->pString .= "<number><style>" . $month . ' ' . $day . "</style></number>";
			if(isset($row['year1']) && $row['year1'])
			{
				$dates[] = "<year><style>" . $this->spCharFormat($row['year1']) . 
					"</style></year>";
				unset($row['year1']);
			}
			if(isset($row['year2']) && $row['year2'])
			{
				$this->pString .= "<volume><style>" . $this->spCharFormat($row['year2']) . 
					"</style></volume>";
				unset($row['year2']);
			}
		}
		else if(isset($row['year1']) && $row['year1'] && $row['miscField3'])
		{
			$monthEnd = $dayEnd = FALSE;
			$month = $this->monthArray[$row['miscField3']];
			unset($row['miscField3']);
			if($row['miscField2']) // start Day
			{
				$day = $row['miscField2'] < 10 ? '0' . $row['miscField2'] : $row['miscField2'];
				unset($row['miscField2']);
				$month .= ' ' . $day;
			}
			if($row['miscField6']) // end Month
			{
				$monthEnd = $this->monthArray[$row['miscField6']];
				unset($row['miscField6']);
				$month .= ' ' . $monthEnd;
				if($row['miscField5']) // end Day
				{
					$dayEnd = $row['miscField5'] < 10 ? '0' . $row['miscField5'] : $row['miscField5'];
					unset($row['miscField5']);
					$month .= ' ' . $dayEnd;
				}
			}
			if($month)
				$dates[] = "<pub-dates><date><style>" . $month . "</style></date></pub-dates>";
			$year = $this->spCharFormat($row['year1']);
			if($row['year3']) // End Year
				$year .= ' ' . $this->spCharFormat($row['year3']);
			$dates[] = "<year><style>" . $year . "</style></year>";
			unset($row['year1']);
		}
		else if(isset($row['year1']) && $row['year1'])
		{
			$dates[] = "<year><style>" . $this->spCharFormat($row['year1']) . "</style></year>";
			unset($row['year1']);
		}
		if(!empty($dates))
			return "<dates>" . join('', $dates) . "</dates>";
		return FALSE;
	}
// grab any stored data for this resource from WKX_import_raw
	function raw($row)
	{
		$recordset = $this->db->select(array('WKX_import_raw'), array('text', 'importType'), 
			"WHERE " . $this->db->formatField('id') . "=" . $this->db->tidyInput($row['resourceId']) . 
			" AND " . $this->db->formatField('importType') . "=" . $this->db->tidyInput('endnote'));
		if(!$this->db->numRows($recordset))
			return FALSE;
		while($rawRow = $this->db->loopRecordSet($recordset))
			$rawEntries = unserialize(base64_decode($rawRow['text']));
		if($rawEntries)
		{
			$rawEntries = explode("\n", $rawEntries);
			array_pop($rawEntries); // always an empty array at end so get rid of it.
			foreach($rawEntries as $entries)
			{
				$entry = explode("=", $entries, 2);
				if(!trim($entry[1]))
					continue;
				if(trim($entry[0]) == 'citation')
					$this->rawCitation = trim($entry[1]);
				else
				{
					$key = trim($entry[0]);
					$value = trim($entry[1]);
					$rawEntry[$key] = $value;
				}
			}
		}
		if(isset($rawEntry))
			return $rawEntry;
		return FALSE;
	}
// load default arrays
	function loadArrays()
	{
// need to use English constants for ENDNOTE
		include_once("languages/en/CONSTANTS.php");
		$constants = new CONSTANTS_en();
		$constants->convertNumbers();
		$this->editionArray = $constants->cardinalToOrdinalWord();
		$this->monthArray = $constants->monthToLongName();
	}
// Error handling
	function failure($error)
	{
		$this->template->setVar('body', $error);
		$pString = $this->template->process();
		include_once("core/html/CLOSE.php");
		new CLOSE($this->db, $pString);
	}
}
?>
